﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace MD5Checksum
{
    class Helper
    {
        public static string GetMd5HashFromFile(string fileName)
        {
            try
            {
                //FileStream file = new FileStream(fileName, FileMode.Open);
                //FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                FileStream file = File.OpenRead(fileName);
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();

                //StringBuilder sb = new StringBuilder();
                //for (int i = 0; i < retVal.Length; i++)
                //{
                //    sb.Append(retVal[i].ToString("x2"));
                //}
                //return sb.ToString();

                return BitConverter.ToString(retVal).Replace("-", "").ToLower();
            }
            catch (Exception ex)
            {
                File.AppendAllText("MD5Checksum.log", DateTime.Now.ToString("yyyyMMddHHmmss") + ": " + ex.Message + Environment.NewLine);
            }
            return string.Empty;
        }

        public static IList<string> GetDirFiles(string dir, bool isRecursive)
        {
            return GetDirFiles(dir, isRecursive, 0);
        }

        public static IList<string> GetDirFiles(string dir, bool isRecursive, int dateFilter)
        {
            IList<string> result = new List<string>();
            DirectoryInfo dirInfo = new DirectoryInfo(dir);
            FileInfo[] files = dirInfo.GetFiles();
            foreach (FileInfo file in files)
            {
                int dateModified = Convert.ToInt32(file.LastWriteTime.ToString("yyyyMMdd"));
                if (dateModified >= dateFilter)
                    result.Add(file.FullName);
            }
            if (isRecursive)
            {
                DirectoryInfo[] childDirs = dirInfo.GetDirectories();
                foreach (DirectoryInfo childDir in childDirs)
                    result = Concat(result, GetDirFiles(childDir.FullName, isRecursive, dateFilter));
            }

            return result;
        }

        public static IList<string> GetAllFiles(bool isRecursive, params string[] args)
        {
            return GetAllFiles(isRecursive, 0, args);
        }

        public static IList<string> GetAllFiles(bool isRecursive, int dateFilter, params string[] args)
        {
            IList<string> result = new List<string>();

            foreach (string arg in args)
            {
                if (Directory.Exists(arg))
                {
                    result = Concat(result, GetDirFiles(arg, isRecursive, dateFilter));
                }
                if (File.Exists(arg))
                {
                    FileInfo fInfo = new FileInfo(arg);
                    int dateModified = Convert.ToInt32(fInfo.LastWriteTime.ToString("yyyyMMdd"));
                    if (dateModified >= dateFilter)
                        result.Add(arg);
                }

                string appPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
                string pathWithArg = appPath + arg;
                if (Directory.Exists(pathWithArg))
                {
                    result = Concat(result, Helper.GetDirFiles(pathWithArg, isRecursive, dateFilter));
                }
                if (File.Exists(pathWithArg))
                {
                    FileInfo fInfo = new FileInfo(pathWithArg);
                    int dateModified = Convert.ToInt32(fInfo.LastWriteTime.ToString("yyyyMMdd"));
                    if (dateModified >= dateFilter)
                        result.Add(pathWithArg);
                }
            }

            return result;
        }

        public static string GenerateMD5Checksum(bool isRecursive, int dateFilter, string[] extFilters, string delimited, params string[] args)
        {
            IList<string> files = GetAllFiles(isRecursive, dateFilter, args);
            StringBuilder sb = new StringBuilder();
            foreach (string file in files)
            {
                if (extFilters.Length > 0 && !IsContains(extFilters, Path.GetExtension(file)))
                    continue;
                string md5 = GetMd5HashFromFile(file);
                sb.Append(md5).Append(delimited).Append(file).Append(Environment.NewLine);
            }
            return sb.ToString();
        }

        public static bool IsContains(string[] arr, string st)
        {
            foreach (string s in arr)
            {
                if (s.Equals(st))
                    return true;
            }
            return false;
        }

        public static IList<string> Concat(IList<string> set1, IList<string> set2)
        {
            IList<string> result = new List<string>();
            foreach (string st in set1)
                result.Add(st);
            foreach (string st in set2)
                result.Add(st);
            return result;
        }
    }
}
